/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
#include <GL/gl.h>
#include <GL/glut.h>
#include "Devices.hpp"
#include "GLDisplay.hpp"
#include "Machine.hpp"
#include "picking/glutils.hpp"

using namespace MuRo;

/******************************************************************************/

const int CPositionDevice::infoBarHeight=15;
const int CPositionDevice::infoBarMinWidth=60;

CPositionDevice::CPositionDevice(MaCI::Position::CPositionClient *positionClient, 
                CMachine* machine)
:CDevice(positionClient, GIMI_PROTOCOL_MACI_POSITION, machine),
positionX(0),
positionY(0),
heading(0),
infoBarWidth(0),
showHistory(false),historyLifetimeS(10)
{
  positionClient->SetPositionClientCallback(this);
}
      
void CPositionDevice::Draw(const TViewParams &view)
{
  if (enabled)
  {
    drawUnit(view);
  }
}

void CPositionDevice::DrawPickable(const TViewParams &view)
{
  if (enabled)
  {
    drawUnit(view, true);
  }
}

      
void CPositionDevice::OnPositionDataEvent(const MaCI::Position::CPositionData& data, 
                      unsigned int seq, MaCI::Position::CPositionClient& client,
                      void * userPtr)
{
    Lock();
    positionX=data.GetPose2D()->x;
    positionY=data.GetPose2D()->y;
    heading=data.GetPose2D()->a;
    

    
    history.push_front( PoseWTime( *(data.GetPose2D()),
                        gim::time(true, historyLifetimeS*1000)));
    
    gim::time current(true);
    while (history.size()>1 && history.back().time<current)
    {
      history.pop_back();
    }
    Unlock();
}

void CPositionDevice::drawUnit(const TViewParams &view, bool selectionMode)
{
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  
  glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT);
  
  if (machine->IsSelected())
  {
    glColor3f(UNIT_COLOR_SELECTED);
    glLineWidth(LINE_WIDTH_SELECTED);
  } else {
    glColor3f(UNIT_COLOR_DESELECTED);
    glLineWidth(LINE_WIDTH_DESELECTED);
  }
  
  if (selectionMode) {
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  } else {
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  }
  
    Lock();
  if (IsPointVisible2D(view, positionX, positionY))
  {
    //if machine is visible, draw normally
    int sx, sy;
    double sz;
    glToScreen(positionX, positionY+0.4, 0, sx, sy, sz);
    drawInfo(view,sx, sy);
    glTranslatef(positionX, positionY, 0);
    glRotatef(heading*(180.0/M_PI),0,0,1);
    drawIcon(view,selectionMode);
  } else {
    //if not visible, draw pointer to the side of the view
    drawPointer(view,selectionMode);
  }
  
  glLoadIdentity();
  if (showHistory)
    drawHistory(view);

  Unlock();
  
  glPopAttrib();
  glPopMatrix();
  
}

void CPositionDevice::drawIcon(const TViewParams &view, bool selectionMode )
{ 
  //TODO: choosing icon according to machine type
  
  
  //draw robot
  glBegin(GL_POINTS);
  glVertex2f(0,0);
  glEnd();
  
  glBegin(GL_TRIANGLES);
  glVertex2f(0.25,0);
  glVertex2f(0.05,-0.1);
  glVertex2f(0.05,0.1);
  glEnd();
  
  float step=2*M_PI/32;
  
  glBegin(GL_POLYGON);
  //glVertex2f(0,0);
  for (float a=0;a<2*M_PI;a+=step)
  {
    glVertex2f(cos(a)*0.25,sin(a)*0.25);
  }
  glEnd();
  
}

void CPositionDevice::drawPointer(const TViewParams &view, bool selectionMode)
{
  //TViewParams view=display->GetViewParams();
  
  float a=atan2(positionY-view.OriginY, positionX-view.OriginX);
  
  float aa=atan2(view.Top-view.OriginY, view.Right-view.OriginX);
  
  float pointerX, pointerY;
  float infoX, infoY;
  //int textW=getTextWidth(GLUT_BITMAP_HELVETICA_10, name.c_str());
  
  if ( (a > aa && a < (M_PI-aa)) || (a < -aa && a > (-M_PI+aa)) )
  {
    if ( a > aa && a < (M_PI-aa) ) {
      pointerY=view.Top;
      infoY=view.Top-60.0/view.Scale;
    } else {
      pointerY=view.Bottom;
      infoY=view.Bottom+60.0/view.Scale;
    }
    pointerX=view.OriginX+(pointerY-view.OriginY)/tan(a);
    infoX=pointerX-1.0*infoBarWidth/view.Scale/2;;
  } else {
    
    if ( a < aa && a > -aa) {
      pointerX=view.Right;
      infoX=view.Right-(infoBarWidth+10.0)/view.Scale;
    } else {
      pointerX=view.Left;
      infoX=view.Left+10.0/view.Scale;
    }
    pointerY=view.OriginY+(pointerX-view.OriginX)*tan(a);
    infoY=pointerY+20.0/view.Scale;
  }
  
  int sx, sy;
  double sz;
  glToScreen(infoX, infoY, 0, sx, sy, sz);
  drawInfo(view, sx, sy);
  
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  
  glTranslatef(pointerX, pointerY, 0);
  glRotatef(a*(180.0/M_PI), 0, 0, 1);
  
  
  glBegin(GL_TRIANGLES);
  glVertex2f(0,0);
  glVertex2f(-50.0/view.Scale ,15.0/view.Scale);
  glVertex2f(-50.0/view.Scale,-15.0/view.Scale);
  glEnd();
  
  glPopMatrix();
  
}

void CPositionDevice::drawInfo(const TViewParams &view, int x, int y)
{
  //draws a hud box with robots name, status (driving, idling, etc) and drive mode (auto/man)
  
  if (!infoBarWidth)
  {
    infoBarWidth=getTextWidth(GLUT_BITMAP_HELVETICA_10, machine->GetName().c_str())+6;
    if (infoBarWidth < infoBarMinWidth)
      infoBarWidth=infoBarMinWidth;
  }

  int screenW=view.Width;//display->GetSize().GetWidth();
  int screenH=view.Height;//display->GetSize().GetHeight();
  
  glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_TRANSFORM_BIT);
  
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  
  gluOrtho2D(0,screenW,0,screenH);
  
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  
  glTranslatef(x,y,0);
  
  glDisable(GL_DEPTH_TEST);
  
  glColor3f(0.4,0.4,0.4);
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  
  // Draw the filled polygon in grey
  glRecti(0, infoBarHeight/2, infoBarWidth, -infoBarHeight/2);
  
  glColor3f(0.9,0.9,0.9);
  
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  
  drawText(3,-3,0,GLUT_BITMAP_HELVETICA_10, machine->GetName().c_str());
  

  /*
    // TODO::::
    // DISABLED PRINTING THE MACHINE STATUS AS IT HAS NOTHING TO DO WITH REALITY!
    //
    glRecti(1,1,13,-13);
    if (machine->GetOperationMode()==KOperModeCoordDrive)
    {
    drawText(3,-10,0,GLUT_BITMAP_HELVETICA_10, "A");
    } else if (machine->GetOperationMode()==KOperModeManualDrive) {
    drawText(3,-10,0,GLUT_BITMAP_HELVETICA_10, "M");
    } else {
    drawText(3,-10,0,GLUT_BITMAP_HELVETICA_10, "-");
    }
    
    if (machine->GetStatus()==KStatusIdle)
    {
    drawText(18,-10,0,GLUT_BITMAP_HELVETICA_10, "Idle");
    } else {
    drawText(18,-10,0,GLUT_BITMAP_HELVETICA_10, "Working");
    }
  */
  
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glPopAttrib();
}

void CPositionDevice::drawHistory(const TViewParams &view)
{
  //Lock(); ///< removed the locks, the locks are now in the machines draw commands
  std::list<PoseWTime>::iterator i;
  glColor3f(0.7,0.7,0);
  glBegin(GL_LINE_STRIP);
  for (i=history.begin(); i!=history.end(); i++)
  {
    glVertex3f(i->pose.x,i->pose.y,0);
  }
  glEnd();
  //Unlock();
}

bool CPositionDevice::IsPointVisible2D(const TViewParams &view, float x, float y)
{
  if ( x >= view.Left && x <= view.Right && y >= view.Bottom && y <= view.Top)
    return true;
  return false;
}

/******************************************************************************/
/******************************************************************************/


CRangingDevice::CRangingDevice(MaCI::Ranging::CRangingClient *rangingClient,
                               CMachine* machine)
:CDevice(rangingClient, GIMI_PROTOCOL_MACI_RANGING, machine)
{
  rangingDisplay=new CRangingDisplay();
  rangingClient->SetRangingClientCallback(rangingDisplay);
}

void CRangingDevice::Draw(const TViewParams &view)
{
  if (enabled)
  {
    rangingDisplay->Draw();
  }
}

void CRangingDevice::SetPositionDevice(CPositionDevice *position)
{
  positionDevice=position;
  rangingDisplay->SetReferencePosition(
                (MaCI::Position::CPositionClient*)(positionDevice->MaCIClient));
  dPrint(1,"Set Reference position %p", positionDevice->MaCIClient);
}

void CRangingDevice::GetDeviceInformation(int timeout)
{
  MaCI::Ranging::TDeviceInformationLimits l;
  MaCI::Ranging::TDeviceInformationPosition p;
  ((MaCI::Ranging::CRangingClient*)MaCIClient)->GetDeviceLimits(l, timeout);
  ((MaCI::Ranging::CRangingClient*)MaCIClient)->GetDevicePosition(p, timeout);
  rangingDisplay->SetDeviceInformation(l,p);
}

/******************************************************************************/
/******************************************************************************/

CEnergyDevice::CEnergyDevice(MaCI::Energy::CEnergyClient *energyClient, 
                            CMachine* machine)
:CDevice(energyClient, GIMI_PROTOCOL_MACI_ENERGY, machine),
energyLevel(0), maxEnergyLevel(0), energyConsumption(0)
{
  energyClient->SetEnergyClientCallback(this);
}

void CEnergyDevice::Draw(const TViewParams &view)
{
  if (enabled)
  {
    //TViewParams view=display->GetViewParams();
    
    //energy icon size
  #define ICON_W (30.0/view.Scale)
  #define ICON_H (10.0/view.Scale)
    
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    
    //Lock();

    if (energyLevel<0)
      return;
    
    glTranslatef(machine->GetPositionX()-ICON_W/2.0,machine->GetPositionY()-0.3-ICON_H,0);
    
    glBegin(GL_LINE_LOOP);
    
    glColor3f(0.7, 0.7, 0.7);
    glVertex2f(0,0);
    glVertex2f(0,ICON_H);
    glVertex2f(ICON_W,ICON_H);
    glVertex2f(ICON_W,0.0);
    
    glEnd();
  
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glBegin(GL_QUADS);
    
    glVertex2f(ICON_W,ICON_H/3.0);
    glVertex2f(ICON_W,ICON_H/3.0*2.0);
    glVertex2f(ICON_W*1.05,ICON_H/3.0*2.0);
    glVertex2f(ICON_W*1.05,ICON_H/3.0);
    
    glColor3f(1-energyLevel*energyLevel, 1-(1.0-energyLevel)*(1.0-energyLevel), 0);
    glVertex2f(0.0, 0.0);
    glVertex2f(0.0, ICON_H);
    glVertex2f(ICON_W*energyLevel, ICON_H);
    glVertex2f(ICON_W*energyLevel, 0);
    
    glEnd();
    //Unlock();
    
    glPopMatrix();
  }
}

void CEnergyDevice::OnEnergyDataEvent(const MaCI::Energy::CEnergyData &aData, 
                       const unsigned int aDataSequence,
                       MaCI::Energy::CEnergyClient &aEnergyClient,
                       void * userPtr)
{
  if (aData.GetEnergyEvent() && aData.GetEnergyEvent()->type==MaCI::Energy::KEventTypeEnergyData )
  {
    energyLevel=aData.GetEnergyEvent()->energyLevel/100.0;
    maxEnergyLevel=aData.GetEnergyEvent()->energyMax;
    energyConsumption=aData.GetEnergyEvent()->consumption;
  }
}

/******************************************************************************/
/******************************************************************************/

CSpeedCtrlDevice::CSpeedCtrlDevice(MaCI::SpeedCtrl::CSpeedCtrlClient *speedCtrlClient, 
                 CMachine* machine)
:CDevice(speedCtrlClient, GIMI_PROTOCOL_MACI_SPEEDCTRL, machine)
{
  speedCtrlClient->GetSpeedLimits(maxSpeed, minSpeed);
  dPrint(1,"***********************************************************");
  dPrint(1,"GOT SPEED LIMIT max %f %f %f, min %f %f %f",maxSpeed.speed,
         maxSpeed.angularSpeed,
         maxSpeed.acceleration,
         minSpeed.speed,
         minSpeed.angularSpeed,
         minSpeed.acceleration);
}

void CSpeedCtrlDevice::Draw(const TViewParams &view)
{
  //TODO: draw somewhere speeds that are got from speedctrl
  //would show machines speed also if it wasnt under this users control
}


/******************************************************************************/
/******************************************************************************/

CMapDevice::CMapDevice(MaCI::Map::CMapClient *mapClient, 
                        CMachine *machine)
:CDevice(mapClient, GIMI_PROTOCOL_MACI_MAP, machine)
{
  mapDisplay=new CMapDisplay();
  mapClient->SetMapClientCallback(mapDisplay);
  mapDisplay->SetZ(-10);
  waiting=true;
  RunThread();
}

void CMapDevice::Draw(const TViewParams &view)
{
  if (enabled)
  {
    if (waiting)
    {
      int screenW=view.Width;//display->GetSize().GetWidth();
      int screenH=view.Height;//display->GetSize().GetHeight();
      
      glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_TRANSFORM_BIT);
  
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
  
      gluOrtho2D(0,screenW,0,screenH);
  
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
  
      glTranslatef(20,screenH-30,0);
      glColor3f(0,1,0);
      drawText(18,-10,0,GLUT_BITMAP_HELVETICA_10, "Getting the map from server...");
      
      glMatrixMode(GL_MODELVIEW);
      glPopMatrix();
      glMatrixMode(GL_PROJECTION);
      glPopMatrix();
      glPopAttrib();
    } else {
      mapDisplay->Draw();
    }
  }
}

int CMapDevice::ThreadFunction(const int aThreadNumber)
{
  //get whole map from server
  MaCI::Map::CMapData md;
  if (((MaCI::Map::CMapClient*)MaCIClient)->GetMap(md,3000))
  {
    dPrint(1,"**************** GOT MAP *********************");
    mapDisplay->UpdateWholeMap(md);
  }
  waiting=false;
  return 0;
}

/******************************************************************************/
/******************************************************************************/


CCoordinateDriveDevice::CCoordinateDriveDevice(MaCI::CoordinateDrive::CCoordinateDriveClient *coordinateDriveClient, CMachine* machine)
  :CDevice(coordinateDriveClient, GIMI_PROTOCOL_MACI_COORDINATEDRIVE, machine),
   /*editablePath(machine),serverPath(machine)*/path(this),pickingContext(NULL)
{
  coordinateDriveClient->SetCoordinateDriveClientCallback(this);

 

  //serverPath.editable=false;
}

void CCoordinateDriveDevice::SetPickingContext(CGLPickingContext *context)
{
  pickingContext=context;
  path.SetPickingContext(context);
  //editablePath.SetPickingContext(context);

  //NOT THE RIGHT PLACE, But segfaults if in the constructor...
  MaCI::CoordinateDrive::TCoordinateArray coordinates;
  MaCI::Common::TTimestamp tstamp;
  //dPrint(1,"Getting coordinates..");

  MaCI::CoordinateDrive::CCoordinateDriveClient *coordinateDriveClient =
    dynamic_cast<MaCI::CoordinateDrive::CCoordinateDriveClient *> (this->MaCIClient); 
  //Fetch the coordinates, which are already setted (if some)
  if(coordinateDriveClient->GetCoordinates(coordinates,
                                           tstamp)){
    //dPrint(1,"for.. size (%d)",coordinates.size());
    
    for(EACH_IN_i(coordinates)){
      //dPrint(1,"Adding...");
      //dPrint(1,"%f %f ",i->x,i->y);
      path.AddPoint(i->x,i->y);

    }
      

  }


}

void CCoordinateDriveDevice::Draw(const TViewParams &view)
{
  path.Draw(view);
  //editablePath.Draw(view);
  //serverPath.Draw(view);
}

void CCoordinateDriveDevice::OnArrivedToPointEvent(
          const MaCI::CoordinateDrive::CCoordinateDriveData &aData, 
          const unsigned int aDataSequence,
          MaCI::CoordinateDrive::CCoordinateDriveClient &aCoordinateDriveClient,
          void * userPtr)
{
  
}

void CCoordinateDriveDevice::OnCoordinateEvent(
          const MaCI::CoordinateDrive::CCoordinateDriveData &aData, 
          const unsigned int aDataSequence, 
          MaCI::CoordinateDrive::CCoordinateDriveClient &aCoordinateDriveClient,
          void * userPtr)
{
  path.Clear();
  //serverPath.Clear();
  int c=aData.GetCoordinateHeader()->coordinateCount;
  for (int i=0; i<c;i++)
  {
    const MaCI::CoordinateDrive::TCoordinate2D *coord=aData.GetCoordinate(i);;
    //serverPath.AddPoint(coord->x,coord->y);
    path.AddPoint(coord->x,coord->y);
  }
}

void CCoordinateDriveDevice::OnServerStatusMessage(const MaCI::CoordinateDrive::CCoordinateDriveData &aData,
                                                   const unsigned int aDataSequence,
                                                   MaCI::CoordinateDrive::CCoordinateDriveClient &aCoordinateDriveClient,
                                                   void * aUserPtr)
{
  dPrint(6,"Got server status message.");
  /// DO SOMETHING?

}

void CCoordinateDriveDevice::AddPoint(float x, float y)
{
  path.AddPoint(x,y);
  //editablePath.AddPoint(x,y);
}

void CCoordinateDriveDevice::RemoveSelectedPoints()
{
  path.RemoveSelectedPoints();
  //editablePath.RemoveSelectedPoints();
}

void CCoordinateDriveDevice::StartDriving()
{
  MaCI::CoordinateDrive::CCoordinateDriveClient* c=
      (MaCI::CoordinateDrive::CCoordinateDriveClient*)MaCIClient;
  c->RemoveCoordinates();
  path.SendPoints(c);
  //editablePath.SendPoints(c);
  c->SetStart();
}

void CCoordinateDriveDevice::StopDriving()
{
  
}

/******************************************************************************/
/******************************************************************************/


CAlarmDevice::CAlarmDevice(MaCI::Alarm::CAlarmClient *alarmClient, CMachine *machine)
  :CDevice(alarmClient, GIMI_PROTOCOL_MACI_ALARM, machine),pickingContext(NULL)
{
  alarmClient->SetAlarmClientCallback(this);
}


void CAlarmDevice::OnAlarmDataEvent(const MaCI::Alarm::CAlarmData &aData, 
                      const unsigned int aDataSequence,
                      MaCI::Alarm::CAlarmClient &aAlarmClient)
{
  Lock();
  
  CAlarmBalloon *a=new CAlarmBalloon(this, &aAlarmClient, aData);
  
  if (pickingContext)
    a->SetPickingContext(pickingContext);
  /*
  alarm a;
  a.event=*(aData.GetAlarmEvent());
  if (aData.GetTimestamp() )
  {
    a.time=*(aData.GetTimestamp());
  } else {
    MaCI::Common::TTimestamp t;
    t.SetToCurrentTime();
    a.time=t;
  }
  */
  alarmArray.push_back(a);
  
  Unlock();
}


void CAlarmDevice::Draw(const TViewParams &view)
{
//#define BUBBLE_W (10.0/view.Scale)
#define BUBBLE_D (20.0/view.Scale+0.3)
  Lock();
  
  if (alarmArray.size())
  {
    float x=0;
    float y=0;
    
    float step=2.0*M_PI/8.0;
    float angle=M_PI/2.0-(alarmArray.size()-1)*step/2.0;

    x=machine->GetPositionX();
    y=machine->GetPositionY();
    
    std::list<CAlarmBalloon*>::iterator i;
    
    for (i=alarmArray.begin();i!=alarmArray.end();i++)
    {
      (*i)->SetSourcePosition(x+cos(angle+0.05)*BUBBLE_D/2.0,y+sin(angle+0.05)*BUBBLE_D/2.0);
      (*i)->SetPosition(x+cos(angle+0.05)*BUBBLE_D,y+sin(angle+0.05)*BUBBLE_D);
      angle=angle+step;
      (*i)->Draw(view);
    }
    
    
  }
  
  /*
  if (alarmArray.size())
  {
    std::list<alarm>::iterator i;
    
    char c[2]={'!',0};
    
    float step=2.0*M_PI/8.0;
    float angle=M_PI/2.0-(alarmArray.size()-1)*step/2.0;
    
    
    float x=0;
    float y=0;

    x=machine->GetPositionX();
    y=machine->GetPositionY();
    
    for (i=alarmArray.begin();i!=alarmArray.end();i++)
    {
      glPushMatrix();
      
      if (i->event.type==MaCI::Alarm::KEventTypeQuestion)
      {
        glColor3f(1,1,1);
        c[0]='?';
      }else if (i->event.type==MaCI::Alarm::KEventTypeWarning || 
                i->event.type==MaCI::Alarm::KEventTypeError) 
      {
        glColor3f(1,0.6,0.6);
        c[0]='!';
      } else {
        glColor3f(1,1,1);
        c[0]='!';
      }


      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      
      glTranslatef(x,y,0);

      glBegin(GL_TRIANGLES);

      glVertex2f(cos(angle+0.05)*BUBBLE_D/2.0,sin(angle+0.05)*BUBBLE_D/2.0);

      glVertex2f(cos(angle+0.05)*BUBBLE_D,sin(angle+0.05)*BUBBLE_D);
      glVertex2f(cos(angle-0.05)*BUBBLE_D,sin(angle-0.05)*BUBBLE_D);

      glEnd();

      glTranslatef(cos(angle)*BUBBLE_D,sin(angle)*BUBBLE_D,0);

      glBegin(GL_QUADS);

      glVertex3f(-BUBBLE_W, -BUBBLE_W,15);
      glVertex3f(BUBBLE_W, -BUBBLE_W,15);
      glVertex3f(BUBBLE_W, BUBBLE_W,15);
      glVertex3f(-BUBBLE_W, BUBBLE_W,15);
      
      glEnd();
      glColor3f(0,0,0);

      drawText(-3.0/view.Scale,-8.0/view.Scale,15,GLUT_BITMAP_HELVETICA_18,c);

      angle=angle+step;
      glPopMatrix();
    }
    
  }*/
  Unlock();
}

void CAlarmDevice::RemoveAlarm(CAlarmBalloon *alarm)
{
  std::list<CAlarmBalloon*>::iterator i;
    
  for (i=alarmArray.begin();i!=alarmArray.end();i++)
  {
    if ((*i)==alarm)
    {
      alarmArray.erase(i);
      delete alarm;
      break;
    }
  }
}

void CAlarmDevice::SetPickingContext(CGLPickingContext *context)
{
  pickingContext=context;
  
  std::list<CAlarmBalloon*>::iterator i;
    
  for (i=alarmArray.begin();i!=alarmArray.end();i++)
  {
    (*i)->SetPickingContext(pickingContext);
  }
}


/******************************************************************************/
/******************************************************************************/
    
    
